package com.wugh.fast.kernel.core.thread;

import cn.hutool.core.collection.CollectionUtil;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

/**
 * 说明: 上下文封装的回调
 * <pre>
 *     通过{@link ContextHandler 上下文处理器} 解决线程回调时上下文问题
 * </pre>
 *
 * @author wugh
 * @date 2020-01-15 16:53
 */
public class ContextAwareCallable<T> implements Callable<T> {
    /**
     * 默认的上下文处理器
     */
    private static List<ContextHandler> DEFAULT_HANDLERS = Collections.emptyList();
    /**
     * 回调方法
     */
    Callable<T> callable;
    /**
     * 上下文映射
     */
    Map<ContextHandler, Object> contextMap;

    /**
     * 设置默认的处理方法
     *
     * @param handlers
     */
    public static void setDefaultHandlers(List<ContextHandler> handlers) {
        ContextAwareCallable.DEFAULT_HANDLERS = handlers == null ? Collections.emptyList() : handlers;
    }

    /**
     * 构建
     * <pre>
     *     使用默认的上下文处理器,在构建时候,获取上下文列表
     * </pre>
     *
     * @param callable
     * @param <T>
     * @return
     */
    public static <T> ContextAwareCallable<T> build(Callable<T> callable) {
        return new ContextAwareCallable<>(callable, DEFAULT_HANDLERS);
    }

    /**
     * 构建
     * <pre>
     *     使用传入的上下文处理器处理上下文,在构建时候,获取上下文列表
     * </pre>
     *
     * @param callable
     * @param handlers
     * @param <T>
     * @return
     */
    public static <T> ContextAwareCallable<T> build(Callable<T> callable, List<ContextHandler> handlers) {
        return new ContextAwareCallable<>(callable, handlers);
    }

    private ContextAwareCallable(Callable<T> callable, List<ContextHandler> handlers) {
        this.callable = callable;
        this.contextMap = obtainContext(handlers);
    }

    private Map<ContextHandler, Object> obtainContext(List<ContextHandler> handlers) {
        if (CollectionUtil.isEmpty(handlers)) {
            return Collections.emptyMap();
        }
        return handlers.stream()
                .filter(handler -> handler.getContext() != null)
                .collect(Collectors.toMap(handler -> handler, ContextHandler::getContext));
    }


    @Override
    public T call() throws Exception {
        try {
            //设置上下文
            contextMap.forEach(ContextHandler::setContext);
            return callable.call();
        } finally {
            //清除上下文
            contextMap.keySet().forEach(ContextHandler::cleanContext);
        }
    }
}
